README.md (7355B)
1 This sample shows how to set up a simple character controller using the input system. As there is more than one way to do it, the sample illustrates several ways. Each demonstration is set up as a separate scene. The basic functionality in all the scenes is the same. You can move and look around and fire projectiles (colored cubes) into the scene. In some scenes, only gamepads are supported but the more involved demonstrations support several different inputs concurrently. 2 3 # SimpleDemo_UsingState 4 5 [Source](./SimpleController_UsingState.cs) 6 7 This starts off at the lowest level by demonstrating how to wire up input by polling input state directly in a `MonoBehaviour.Update` function. For simplicity's sake it only deals with gamepads but the same mechanism works in equivalent ways for other types of input devices (e.g. using `Mouse.current` and `Keyboard.current`). 8 9 The key APIs demonstrated here are `Gamepad.current` and `InputControl.ReadValue`. 10 11 ```CSharp 12 public class SimpleController_UsingState : MonoBehaviour 13 { 14 //... 15 16 public void Update() 17 { 18 var gamepad = Gamepad.current; 19 if (gamepad == null) 20 return; 21 22 var move = Gamepad.leftStick.ReadValue(); 23 //... 24 } 25 } 26 ``` 27 28 # SimpleDemo_UsingActions 29 30 [Source](./SimpleController_UsingActions.cs) 31 32 This moves one level higher and moves input over to "input actions". These are input abstractions that allow you to bind to input sources indirectly. 33 34 In this scene, the actions are embedded directly into the character controller component. This allows setting up the bindings for the actions directly in the inspector. To see the actions and their bindings, select the `Player` object in the hierarchy and look at the `SimpleController_UsingActions` component in the inspector. 35 36 The key APIs demonstrated here are `InputAction` and its `Enable`/`Disable` methods and its `ReadValue` method. 37 38 ```CSharp 39 public class SimpleController_UsingActions : MonoBehaviour 40 { 41 public InputAction moveAction; 42 //... 43 44 public void OnEnable() 45 { 46 moveAction.Enable(); 47 //... 48 } 49 50 public void OnDisable() 51 { 52 moveAction.Disable(); 53 //... 54 } 55 56 public void Update() 57 { 58 var move = moveAction.ReadValue<Vector2>(); 59 //... 60 } 61 } 62 ``` 63 64 The sample also demonstrates how to use a `Tap` and a `SlowTap` interaction on the fire action to implement a charged shooting mechanism. Note that in this case, we run the firing logic right from within the action using the action's `started`, `performed`, and `canceled` callbacks. 65 66 ```CSharp 67 fireAction.performed += 68 ctx => 69 { 70 if (ctx.interaction is SlowTapInteraction) 71 { 72 StartCoroutine(BurstFire((int)(ctx.duration * burstSpeed))); 73 } 74 else 75 { 76 Fire(); 77 } 78 m_Charging = false; 79 }; 80 fireAction.started += 81 ctx => 82 { 83 if (ctx.interaction is SlowTapInteraction) 84 m_Charging = true; 85 }; 86 fireAction.canceled += 87 ctx => 88 { 89 m_Charging = false; 90 }; 91 ``` 92 93 # SimpleDemo_UsingActionAsset 94 95 [Source](./SimpleController_UsingActionAsset.cs) 96 97 As more and more actions are added, it can become quite tedious to manually set up and `Enable` and `Disable` all the actions. We could use an `InputActionMap` in the component like so 98 99 ```CSharp 100 public class SimpleController : MonoBehaviour 101 { 102 public InputActionMap actions; 103 104 public void OnEnable() 105 { 106 actions.Enable(); 107 } 108 109 public void OnDisable() 110 { 111 actions.Disable(); 112 } 113 } 114 ``` 115 116 but then we would have to look up all the actions manually in the action map. A simpler approach is to put all our actions in a separate asset and generate a C# wrapper class that automatically performs the lookup for us. 117 118 To create such an `.inputactions` asset, right-click in the Project Browser and click `Create >> Input Actions`. To edit the actions, double-click the `.inputactions` asset and a separate window will come up. The asset we use in this example is [SimpleControls.inputactions](SimpleControls.inputactions). 119 120 When you select the asset, note that `Generate C# Class` is ticked in the import settings. This triggers the generation of [SimpleControls.cs](SimpleControls.cs) based on the `.inputactions` file. 121 122 Regarding the `SimpleController_UsingActionAsset` script, there are some notable differences. 123 124 ```CSharp 125 public class SimpleController_UsingActionAsset 126 { 127 // This replaces the InputAction instances we had before with 128 // the generated C# class. 129 private SimpleControls m_Controls; 130 131 //... 132 133 public void Awake() 134 { 135 // To use the controls, we need to instantiate them. 136 // This can be done arbitrary many times. E.g. there 137 // can be multiple players each with its own SimpleControls 138 // instance. 139 m_Controls = new SimpleControls(); 140 141 // The generated C# class exposes all the action map 142 // and actions in the asset by name. Here, we reference 143 // the `fire` action in the `gameplay` action map, for 144 // example. 145 m_Controls.gameplay.fire.performed += 146 //... 147 } 148 149 //... 150 151 public void Update() 152 { 153 // Same here, we can just look the actions up by name. 154 var look = m_Controls.gameplay.look.ReadValue<Vector2>(); 155 var move = m_Controls.gameplay.move.ReadValue<Vector2>(); 156 157 //... 158 } 159 } 160 ``` 161 162 Just for kicks, this sample also adds keyboard and mouse control to the game. 163 164 # SimpleDemo_UsingPlayerInput 165 166 [Source](./SimpleController_UsingPlayerInput.cs) 167 168 Finally, we reached the highest level of the input system. While scripting input like in the examples above can be quick and easy, it becomes hard to manage when there can be multiple devices and/or multiple players in the game. This is where `PlayerInput` comes in. 169 170 `PlayerInput` automatically manages per-player device assignments and can also automatically handle control scheme switching in single player (e.g. when the player switches between a gamepad and mouse&keyboard). 171 172 In our case, we're not getting too much out of it since we don't have control schemes or multiple players but still, let's have a look. 173 174 The first thing you'll probably notice is that now there are two script components on the `Player` object, one being the usual `SimpleController` and the other being `PlayerInput`. The latter is what now refers to [SimpleControls.inputactions](SimpleControls.inputactions). It also has `gameplay` set as the `Default Action Map` so that the gameplay actions will get enabled right away when `PlayerInput` itself is enabled. 175 176 For getting callbacks, we have chosen `Invoke Unity Events` as the `Behavior`. If you expand the `Events` foldout in the inspector, you can see that `OnFire`, `OnMove`, and `OnLook` are added to the respective events. Each callback method here looks like the `started`, `performed`, and `canceled` callbacks we've already seen on `fireAction` before. 177 178 ```CSharp 179 public class SimpleController_UsingPlayerInput : MonoBehaviour 180 { 181 private Vector2 m_Move; 182 //... 183 184 public void OnMove(InputAction.CallbackContext context) 185 { 186 m_Move = context.ReadValue<Vector2>(); 187 } 188 189 //... 190 } 191 ```